home *** CD-ROM | disk | FTP | other *** search
- 386POWER PROGRAMMER GUIDELINES
-
- SMILEY WARNING:
- I use "smileys" (the faces drawn with punctuation marks and other chars
- you must roll your head to the left to see clearly)
- a lot because i like to write as i talk
- and i heavily use pronunciation inflection.
- (read: the things i say, if they are written as they are,sometimes look like
- an offence or a menace, the smiley correct this).
- ;-) or ;) == it's a joke, you know i don't mean exactly this.
- :-) or :) == happy
- :-} or :} == oops!
- :-( == i'm not happy of this
-
- PG-A386 WARNING:
- 386POWER HAS BEEN RATED Programmer Grade - Assembly 386 !!!!! ;-)
- I suppose you know enough of assembly and 386 programming.
- If you don't, bad luck.
-
- PMODE WARNING:
- Since 386Power is sort of PMODE stepbrother i based this
- sort of tech manual on the pmode.doc file included into pmode.zip
- by Thomas "Tran" Pytel, this way it will be easier to get the differences
- between the two extenders.
- You might say i mention Tran too many times (or too few times
- if you are Tran ;) ), fact is that i never read a book about
- 386 protected mode programming, i just looked into tran docs and played
- with pmode, then i found the DPMI docs
- and the Ralph Brown Interrupt List on the internet
- and decided to try to build 386Power.
- Anyway, Tran docs together with the pmode sources were the most complete
- thing i found about protected mode programming with some things
- you hardly find in the docs (like how to set the pages under VCPI).
- If you are familiar with pmode, read carefully, there are some things
- that are similar but a lot different.
-
- ------------------------------------------------------------------------------
- Who did it:
-
- 386POWER (386P for short ) has been conceived and coded
- by Lorenzo Micheletto (that's me) but is not all "my stuff" (besides mostly is).
- It is based on the PMODE386 dos-extender by Tran (a.k.a. Thomas Pytel).
- I used modified algorithms found in PMODE 386 and in some situations
- i copied some chunks of code (i.e. the interrupt redirectors).
- I'm not the guy who reinvent the wheel every time (just NEARLY every time ;) ).
-
- And now a little fairy tale about rampaging mechs ....
- Lorenzo Micheletto (that's me), once an 8086 assembly programmer
- was building a game engine under MS-Dos in the free time to build
- a super beat 'em up game based on rampaging mechs.
- ( but sooner or later you will see MechaFighter IV hit the 'net
- after i make a 'test' game to see what's the limit of 386P )
- After realizing 640k couldn't handle all the graph already produced....
- ( immagine how much memory is needed to store all the sprites and
- composed-sprite data for the 150ton MCT-2S MechTerminator
- when it fires at close range a 500mm ShotCan
- [ binary barrel short range cannon, sort of grown-up shotgun ]
- charged with Depleted-Uranium swarm-bullets )
- ... i tried PMODE (the release with RAW,XMS,VCPI and DPMI support).
-
- But after i discovered some quirks (gasp! my test code crashed
- in strange ways and i was closely following what Tran wrote in the docs)
- i first reversed engineered all PMODE to find out what was going wrong
- then digged in the VCPI and DPMI docs, then changed things here and ...
- ... restarted from zero.
-
- I was shaking the system upside-down a lot,so if something was going wrong, it
- was hard to me understand if was my fault, pmode fault or an interaction bug.
-
- Well, after two months of ripping up PMODE i gave up
- ( i couldn't read Tran mind, so some things looked like a bug to me
- but could be just arcane programming, not to mention i HATE code that
- self- modifies because it easily triggers heuristic antiviral routines)
- and decided to build a similar thing (i already had translated lots of
- code from real-mode-286 to protected-mode-386-with-pmode386, so the
- PMODE API was familiar to me, why change ? )
- that i could understand and fix without problems.
-
- Starting from zero source lines i ended up with this strange thing:
- 386POWER, a dos extender interface a lot similar to PMODE
- (nearly the same API, and some portions of it
- are copied straight from pmode) with only VCPI and DPMI support.
-
- GASP! I started patching a program and ended up with another one!
- (sort of genetic programming technique ;-) )
-
- 386Power checks if a VCPI or DPMI manager is present
- (read: it needs EMM386, QEMM or Windows running in 386 Enhanced Mode)
- and if it finds one it initialize the protected mode environment
- for 32bit FLAT protected mode.
- IRQs are active and redirected as expected.
- ALL interrupt vectors gets copied to the _OldInt table
- (and restored on program termination) so you don't need to save them.
-
- ------------------------------------------------------------------------------
- First of all, the memory layout, as you can guess is nearly the same of PMODE:
-
- Your program will have at least 3 segments
-
- code16 A 16bit segment that holds all the real mode and 16bit protected
- mode init and exit code.
- It has to be the first segment of the EXE.
-
- code32 The huge 32bit segment. You can throw in as much code as will fit
- in low memory (no 64k fixup overflows). If you need more code
- space, you're gonna have to load it into extended memory at runtime
- and use it there.
- Under protected mode, addresses (code and data, they're the
- same memory space) are offset from the beginning of this segment.
- I'll explain later how to access things outside this segment.
-
- codeend This MUST be the last segment in the EXE. It is the base for the
- stack and low memory allocation.
- If you want to add other segments insert them between
- code32 and codeend
-
- two things seems to miss ...
- 1) The STACK...
- The stack is shared by your protected mode program and real mode calls.
- This means it can be at most 64k wide (don't worry it's wide enough).
- The stack region always begins at codeend, and goes on for STACKSIZE paragraphs.
- (a value declared in 386power.inc), but the stack
- you can use under a certain context (prot. or real mode) can be at most
- STACKSLOT paragraphs (more on this later).
-
- 2) The HEAP....
- There are TWO HEAPS you can allocate memory from at run time.
-
- The "Low memory" heap, which covers all conventional memory below A0000h.
- The "Extended memory" heap, which covers all those nice bytes above 1M.
-
- There's a reason for keeping them separate (other than
- that big hole between A0000h and 100000h (which I did not want to fill in or
- rearrange with paging) : DOS can only see the low memory heap.
-
- So in calls where you have to pass buffer addresses, you must pass only buffers
- that you have in low memory.
- Low memory is the place where you would allocate any critical disk or
- TWIN DMA buffers (more on this later).
-
- ------------------------------------------------------------------------------
- VIRTUAL REGISTERS
- You call real mode interrupts and far routines with "virtual registers".
- Memory images of the registers as they will be set for the real mode int.
- When the mode-switch occours the current values are pushed into the stack
- the mode switch occours & the new register values are loaded from
- the virtual registers (actually just a table of dwords used by int 32h
- and int 33h mode switch routines)
-
- ------------------------------------------------------------------------------
- Details of runtime:
-
- After initialization of the protected mode environment
- 386POWER will call a label called _Main located in the code32 segment
- (so place _Main: where you want to start your code)
-
- When _Main is reached you can assume that:
- 1) The stack is set up in the first slot (more on this later).
- 2) The interrupts are disabled (and have been all the way from real mode) just
- in case theres something you want to do first.
- 3) CS points to the code segment you're running in (code32)
- thru a selector set up by 386POWER.
- 4) DS,ES,FS, and SS point to an alias of the code segment (same memory). (In
- case you don't remember, you can NEVER write to a CS: override in protected
- mode, only read or execute are allowed in a protectded mode code segment).
-
- N.B. Both selectors in 3) and 4) are set with a 4Gigabytes limit
- soyou can stuff anything you want into them.
- 5) GS is a segment that's 4Gigabyte wide but starts at absolute 0.
- This is of course useful for accessing the real mode dos data area, or
- the BIOS data area, or the PSP, etc...
- 6) The TYPEMATIC RATE is set to minimal values
- (this is very useful if you are gonna perform "raw keyboard" input)
- 7) ALL interrupt vectors are copied to the _OldInt table
- (they will be restored on interrupt termination)
- so you can change the dos interrupt vectors without having to be worried
- to save 'em.
- 8) If you run under DPMI, 386P tries to lock all memory allocated
- but doesn't care if it has been successful or not
- (i do this just to reduce disk swapping to the minimum).
- If you need locked memory (i.e. for IRQ handling) use the DPMI functions
- if you detect DPMI (check the _386Man var.).
-
-
- Selectors:
-
- There are three main selectors you have to know.
- _SelCode, _SelData, and _SelZero are 16bit word vars you can access to get
- the selector values for the code, data, and zero (GS) segments respectively.
- When 386power pass control to _main you can assume
- CS=_SelCode, DS=ES=FS=SS=_seldata, and GS=_selzero.
- You can change the segregs if you wish (for example to do a REP MOVS in the zero seg).
- But the 386POWER routines and ints expect the segregs to be these values
- (except for the special case of SS into an ISR).
- And these MUST be the values when you jump to '_Exit' to return to DOS.
- Another thing that is assumed by 386POWER is DF=0
- (direction flag is clear (like the CLD instruction)).
- You can perform STD, but before calling 386POWER stuff you have to
- "re-set" the direction flag with CLD.
-
- Linear & relative addresses:
-
- All addresses of thing declared in code32 are
- RELATIVE to the beginning of the code32 segment
- (which could start anywhere in low memory).
- nearli all the system code expects addresses that are code32 relative.
-
- For this reason, you must adjust any physical memory pointers
- before you use them.
- That is, to access something at linear address A0000h
- (A000:0000, in 16 bit seg:ofs notation) you can use GS
- (it is loaded with the _SelZero selector) and write GS:0A0000h.
-
- If you want to write to A0000h using the default data segment
- it will not be at DS:A0000, but at
- DS:(A0000h - linear_address_of_the_beginning_of_Code32).
- And this linear_address_of_the_beginning_of_Code32
- is stored in a variable called '_Code32Base'.
- So if the segment code32 is 1F43, the linear address will be 1F430h
-
- To get a pointer to A0000h, you would do something like:
-
- mov eax,0A0000h
- sub eax,_Code32Base
-
- This function is provided as a macro in 386power.inc
- (copied straight from pmode together with the protected mode ISR
- handlers :} )
- together with the macro to go the other way, relative address to linear.
- Of course, if you address something with GS (assuming GS is _SelZero)
- you can use the actual linear address.
- The linear address for code16 is also provided in _Code16Base.
- As well as the linear address of the PSP in '_PSPBase'.
- The linear addresses of code16 and PSP will always be less than code32.
-
- To access them (memory pointed to by them, these vars are in code32), you will
- have to use one of two methods. One is easy enough, just use the GS segment.
- Or you could use negative indexes from the normal segment, causing a
- 4Gbyte wraparound (a lot like the 64kbyte wraparound under real mode).
- However it is rare to access things outside code32, so my advice is to use GS
- to make things clear and as a remainder of things "done outside code32".
-
-
- Memory where is my memory?
-
- As for the memory. You have two heaps, into low and high (extended) memory.
- Each of which is guaranteed to be at least as much as you specified in LOWMIN
- and EXTMIN in 386power.inc, the startup code will grab all low memory for you
- (because it's meant to run standalone), and it will attempt
- to grab all the high memory it can.
- Two dword vars hold information about each memory area. _LoMemBase and
- _LoMemTop specify the base and top of the low memory pool as relative
- addresses (ready to use, no adjustment needed).
- The total amount of low memory available in bytes is _LoMemTop - _LoMemBase
- (notice _LoMemTop points to one byte beyond the last available byte).
- The _GetLoMem routine is a very simple routine that takes a length in EAX
- and checks to see if there is enough low memory.
- If there is enough, it adds the length to _LoMemBase and
- returns a pointer (code32 relative, ready to use) in EAX
- to the low memory block along with the carry flag clear.
- If it finds not enough memory, it returns with the carry flag set.
- _HiMemBase, _HiMemTop, and _GetHiMem are the same thing for high memory.
- Then there is the _GetMem routine that first tries to allocate
- low memory and if this fails it tries high memory.
-
-
- Calling real (actually quite virtual) mode:
-
- You can call real mode, and back. This is only provided so that
- you can call real mode interrupts, and routines that
- you can't recode in protected mode.
- Keep these cross-mode calls to the minimum because they eat lots of cpu time
- and can raise some nasty interaction bugs.
- You can call real mode interrupts or procedures from protected mode
- through INT 32h (call real mode far proc), and INT 33h (call real mode int).
-
- These interrupts are only available to the PROTECTED MODE part of your program.
-
- In REAL MODE, there is a ANOTHER INT 32h that you can use
- to call a protected mode routine.
- Don't confuse the two INT32s with each other, though they do basically
- the same thing BUT THEY ARE NOT THE SAME THING AND THEY DO DIFFERENT THINGS.
- The "int 32h from real mode" doesn't use virtual registers, no register
- parameter passing is possible it is available
- just to implement sort of callback system.
-
- To pass register values from protected mode to real mode and back
- you use 'virtual registers'.
- These 'virtual registers' are merely memory images of EAX,EBX,ECX,EDX,ESI,EDI,
- EBP,DS,ES,FS,and GS. AL and AH and AX and BL ... etc ... are there too, and
- they share the appropriate memory space with each other so if you change the
- 'virtual' AH register, the 'virtual' AX and EAX registers will be changed
- accordingly.
- There are no SS,ESP,CS,EIP registers. CS:EIP is taken from the real mode int
- vector table for int calls, and passed in the real CX:DX registers for a procedure call.
- SS:ESP is set up by 386POWER together with the extended memory manager
- providing protected mode services.
-
- @ INT 33h from prot. mode: Do a real mode interrupt.
- AL=interrupt you want to do. All V86??? general and segment registers will
- be passed to the real mode handler. They will also be passed back as the
- return values into the virtual register.
- The carry, zero, aux, parity, sign, and overflow flags will
- be passed back as the actual CPU flags. The real mode interrupt will be
- called with interrupts disabled (as it is usually). Keep in mind, no CPU
- registers will be modified (except the flags mentioned). Only their V86???
- images will be changed by the real mode int handler.
-
- @ INT 32h from prot. mode: Call a real mode far procedure.
- CX:DX=seg:off you want to call. The register passing works just like INT33.
- Except that the interrupt flag will be preserved across the call to real
- mode (but not back, the IF flag will be in the same state as it was before
- the int).
-
- @ INT 32h from real mode: Call a pmode procedure.
- EDX=off. A 32bit offset in the code32 segment. The register passing works
- just like for the other INT32 in pmode, except that
- register (real or virtual they are) ARE NOT PASSED TO OR FROM
- the prot. mode routine. Upon entry to the routine, the system standard
- things are set. That is:
- CS=_SelCode, DS=ES=FS=SS=_SelData, GS=_SelZero, DF=0 (CLD).
- And they must be that when the thing executes its RET (not RETF).
- But registers and flags won't be passed as happens
- on the int32 from prot. mode. (the real mode int32 is left as a
- quick way to implement callbacks and just these)
-
-
- DPMI and IRQs:
-
- Upon startup, all the interrupt vectors for IRQs point to routines that
- redirect the IRQs to their default real mode handlers. You can hook into any
- IRQ you want. There are two dword pointers that allow you to get and set IRQ
- vektorz. _GetIRQ and _SetIRQ point to routines to get and set the
- relative address of the handler for specific IRQs within the code32 segment.
- To get the address of a handler, just do a 'call _GetIRQ' with BL set to the
- IRQ num you want (0-15). EDX will be returned pointing to its current handler.
- To set an IRQ, pass BL again as the IRQ number, and EDX as the offset of the
- new handler. You can chain to the old handler if you want just by jumping to
- the old address when your handler is done processing.
-
- When your IRQ handler is called, you can be sure of ONLY TWO THINGS. The IF
- flag is clear and CS is loaded with _SelCode.
- All the general regs and segregs should be treated as undefined.
- Even SS cannot be trust, because under DPMI it is set to a little
- "interrupt stack" set up by DPMI.
- In other words ... DON'T CHANGE STACK!!!!
-
- Another consideration for DPMI is the IF flag. According to DPMI specs, only
- CLI, STI, and INT 31h functions AX=900h and AX=901h should be counted on to
- modify the interrupt flag (POPF(D) and IRET(D) should not). This is because
- certain DPMI systems might have to virtualize the interrupt flag, and keep the
- real flag enabled at all times (but don't worry, if the 'virtual' flag is
- clear, your program will not get any IRQs). In practice, certain DPMIs do
- allow IRET(D)s and POPF(D)s to modify the virtual interrupt flag. But this is
- inconsistent across them. So you should follow these rules:
-
- @ CLI and STI are allowed, and do their functions.
- @ Don't assume anything about POPF(D) and IRET(D) and the interrupt flag.
- @ Don't assume the interrupt flag PUSHF(D) stores on the stack is correct,
- it might be the real flag or the 'virtual' flag.
- @ These DPMI INT 31h functions are supported under VCPI too
- (by way of the 386POWER interface).
- ) AX=900h: Get state of IF and disable it. Returns AL set to the IF flag.
- ) AX=901h: Get state of IF and enable it. Returns AL set to the IF flag.
- ) AX=902h: Only returns AL set to the IF flag (0=disabled, 1=enabled).
- @ At the end of an IRQ handler, put a STI. When the handler is called, flags
- are automatically disabled.
- If you do not reenable them, and neither does the IRETD...
- Well... under some systems it will run and on other it will hang.
-
-
- The stack:
-
- 386POWER uses one major stack for both pmode and real mode. This stack is
- always located in low memory (always locked under DPMI).
- The size of the stack is set as STACKSIZE in 386power.inc .
- There is another value there called STACKSLOT,
- this is what must be explained.
-
- When a mode switch occurs, the new stack is the old stack base minus
- STACKSLOT paragraphs. The stack base is the stack location when your program
- starts. And it is only modified by mode switches.
- That is the stack uses STACKSIZE paragraphs and it is "sliced"
- into slots STACKSLOT wide.
- Your main program uses just one stack "slot" and when a mode switch occours
- another "slot" is used as stack, then returning from the mode switch
- the stack becomes the old "slot".
- Into each slot you can safely allocate local variables on the stack
- referencing them with esp ad ebp without having to worry of mode switches
- or reflected irqs triggering a mode switch.
- Every time you switch mode a new slot is used and when you "get back"
- to the caller, the caller "slot" becomes the stack.
-
- So if STACKSIZE = 4000 and STACKSLOT=1000
- your main program cau use up to 1000 bytes
- If a mode switch occours, a news stack is set up and it is wide
- 1000 bytes too.
-
- Let's make an example:
-
- Immagine the following "chunks of code"
- A is the main program
- B is a real mode routine
- C is a real mode timer driven interrupt service routine
- D is a protected mode routine
-
- To describe the stack status we will use the following notation:
-
- XYZ
- 123--- a stack structure with six slots and slots 1,2,3 "in use"
- where 3 is the "active stack" and is in use by the Z subroutine
-
- 1] A is running
-
- A
- 1-----
-
- 2] A calls B (mode switch)
-
- AB
- 12----
-
- 3] B calls D (mode switch)
-
- ABD
- 123---
-
- 4] C triggered by timer interrupt (unexpected mode switch you cannot control)
-
- ABDC
- 1234--
-
- 5] interrupt handler returns
-
- ABD
- 123---
-
- 6] D returns
-
- AB
- 12----
-
- 7] B returns
-
- A
- 1-----
-
- As you can guess, you'd better keep enough slots available because
- if too many mode switch "accumulates" the stack structure will break.
- Follow this rule of the thumb:
- slots = maximum_number_of_cross_mode_switches +
- maximum_number_of_irq_can_nest_between_mode_switches
-
- The best way to minimize IRQ problems is the use of TWIN IRQ handlers
- (two different IRQ ISR routines, one coded for real mode, the other coded
- for protected mode, this way you are sure no mode switches
- will happen because of interrupts triggered by not-deterministic events).
- If you really have to switch mode, keep the Interrupt flag disabled
- to prevent "unexpected irq stackings".
-
-
- Under DPMI things are slightly different but the rule
- "the less mode switches, the better" is still true.
- DPMI handles stack switching on its own, any IRQ causes a switch
- to a totally different stack provided by DPMI (argh!), this is the main
- reason i had to stick with the "slotted stack" model as in pmode
- and keep a var to point to the "next slot" to support int32h/33h
- in protected mode from within interrupts.
- Under real mode irqs and interrupts, if you want to call the "old"
- inteerupt handler, instead of having to store the address somewhere
- every time, just call the equivalent entry stored into the _OldInt table
- (it's the same table used by INT 33h from protected mode).
-
- To summarize:
- @ In an IRQ handler, DON'T switch off the stack it is entered with. Which is
- not guaranteed that SS=_seldata.
- @ Don't do more nested calls across modes than (STACKSIZE/STACKSLOT)-1.
- (-2 be totally safe).
- @ You CAN safely assume SS=_seldata in protected mode only in your main stream
- of execution, and in routines that are called with INT32 from real mode.
- @ Consider your maximum effective stack size to be STACKSLOT.
- @ You CAN call across modes using INT32/33 from an IRQ handler in both real
- and protected mode, but remember this takes time
- (giving IRQs enough time to stockpile if they are fast enough ).
- @ Under real mode IRQ, if you want to call directly the "old" interrupt
- just perform the following actions:
- pushf
- call dword ptr cs:[offset _OldInt + INT_NUM*4]
-
- Exceptions:
-
- Are handled entirely by the DPMI host in those systems.
- In VCPI, exceptions 0-5 and 7 are reflected to real mode
- just like IRQs would be.
- Exceptions 8 and 9-1fh cause immediate termination
- (maybe in future releases i will include some debug messages when
- terminating due to an exception).
-
- ------------------------------------------------------------------------------
- Potential DMA problems:
-
- As you know, the DMA controllers in the PC use all physical addresses.
- Nothing but the processor itself knows how linear memory is arranged in the
- physical memory banks. When paging is disabled, the relationship is very
- simple. The linear address is always the same as the physical address. But
- when you enable paging, that could get all screwed up.
- Under VCPI and DPMI paging IS enabled. (bad luck, uh?)
-
- You can almost definately count on extended memory addresses
- not being consistent with their physical addresses.
- Low memory however, will usually map perfectly to its physical addresses.
- Usually i said, NOT always.
-
- The point is that you shouldn't use "raw" DMA under VCPI and DPMI.
-
- To handle DMA you can try to make tricky things or you can follow the
- Virtual DMA Specification (VDS). This is the recommended way of handling DMA
- under VCPI and DPMI. See the Ralph Brown interrupt list for INT 4Bh
- for more info.
-
- A future release of 386P will include VDS support thru standard routines
- as soon as i find the best way to handle some quirks.
-
- ------------------------------------------------------------------------------
- And now to discuss some of the finer points of different protected mode
- environments:
-
- VCPI:
-
- VCPI is nearly "raw" mode. The CPL is 0, and there is nothing scrutinizing
- the execution of your code. Paging is enabled, but if you want
- you can mess directly with page physical addressed.
- The problem comes with the way VCPI compatibility works. To call a real mode
- interrupt or procedure, we have to pass protected mode control back to the
- VCPI server. This comes out to one thing. IRQs that occur in a real mode call
- will NOT make it to your protected mode handler. It's just the way VCPI works.
- Under VCPI the real mode interrupt table and the protected mode
- interrupt table belongs to different Task Segment Descriptors.
-
- @ Do the IRQ handler in real mode. That way, it will always be called no
- matter what is in control. But this seems to defeat the purpose of protected
- mode. And if this is a timing critical IRQ, you have a problem because passing
- control from a program (prot. mode) to the VCPI server to execute the real mode
- IRQ callback takes a bit of time. Not a terrible amount, but it is a delay.
-
- @ Do the IRQ handler in protected mode, and keep real mode calls to a minimum.
- For example, disable all but the critical IRQs to your program. And try to
- handle as many as you can in pmode. (You can read the keyboard direct from the
- hardware can't you. And you do know how to output FFh to A1h and FDh to 21h).
- But remember one thing... When you go to do a real mode call (DOS file call or
- something else you can't do yourself). Whatever the hardware cause of your IRQ
- will still be active. And if an IRQ occurs in real mode, and there is no real
- mode handler for it. Well, you know... So you either put in some valid real
- mode handler that may merely set a flag that you have an IRQ to service. Or
- disable the source of the IRQ (mask it off at 21h or A1h).
-
- @ Use TWO irq handlers (one in real mode and one
- in protected mode ) to handle the same data structure
- to pass data to/from the main program.
- It is harder to code but a lot faster that "switchy" stuff.
-
- ------------------------------------------------------------------------------
- DPMI:
-
- DPMI is not that bad. It could be a little more consistent across
- its implementations and let you select CPL0 for "trusted" applications.
- I don't like the overhead imposed by CPL3
- (in CPL3, certain instructions have to be emulated by software).
- Multitasking virtual machines in general are not that hot
- when you're trying to do a timing critical action game.
-
- One really annoying problem with DPMI is that current implementations are
- far from perfect.
- QDPMI 1.01 for example, dies when an IRQ occurs in a prot. mode
- call from a real mode IRQ.
- DPMI docs say this shouldn't happen, and it doesn't under Windows 3.1 DPMI
- implementation.
- The Windows 3.1 DPMI is a little better but has lethal quirks
- (try to make coexist paging and Virtual Dma Support if you don't believe me).
-
- While testing the 386power alpha release the DPMI startup used to go bonkers
- doing quite funny things, then i discovered that the "installation check"
- function wrongly reported DPMI 1.0 as the server while
- Windows 3.1 supports DPMI 0.9 ...
- Gasp! My code was optimized to take advantage
- of the extra function provided by DPMI 1.0 if present and so ...
-
- Hmm, another little problem is that I'm not sure how many DPMIs out there
- actually reflect IRQs to real mode if they occur in protected mode.
- Windows 3.1 seems to send them all over as it should.
- According to Tran QDPMI 1.01 sends IRQ1, but not IRQ0.
- And it also doesn't seem to pass IRQs that occur in real mode
- through their protected mode handlers, while Windows 3.1 does.
-
- If you code for VCPI, you must support interrupt reflection by yourself :-(.
-
- Under DPMI, the dpmi server should reflect interrupts for you
- (as happens under Win 3.1) but if it doesn't ... you can't bypass it
- to reflect things yourself (damn!).
- I tried to do it, but strange things happened, my antivirus started
- yelling like a maniac about unbeliavable viral attacks
- ( programs trying to become resident thru interrupt handling routines
- and tunneling from CPL3 to CPL0 )
- and the dmpi server got nuked.
-
- ------------------------------------------------------------------------------
- Some misc notes:
-
- @ Under VCPI, 386Power will map as much extended memory as it can, up to
- 64M without allowing the page tables to use up more memory than would leave
- LOWMIN. Allocating up to 64M means that extended memory under VCPI
- can be at most 63M (even if there is more available).
-
- @ Before exiting your program, you do NOT need to restore any vectors
- (protected or real mode) nor the typematic rate.
- And you do not have to restore the IRQ masks at 21h and A1h (PMODE stores
- them before jumping to _main, and restores them before exiting).
- BUT if you reprogrammed the irq8/int70h timer interval, set it back to its
- initial value
- (the irq0/int8 is automatically set back to 18.2 Hz by the _Exit routine).
-
- @ If you're gonna add other 16bit segments, put them in between code32
- and codeend.
-
- @ Remember that upon reaching '_Main', interrupts are still disabled. Don't
- forget to do the STI.
-
-
- INTERSEGMENT ACCESS:
- Sometimes some variables declared in Code32 are accessed
- from Code16 (eech!) as bad as it can be, it saved me lots of
- segment swapping.
- I learned this trick looking into PMODE386 and decided to use it
- because even if it causes quite an headache to follow the code
- it saves from the problems you run into when you swap segment register
- and mode frequently, but remember the following rules:
- a)
- When you do this, it is better to use a
- segment override to indicate what segment you are using.
- i.e if in code16 you write DS:V86eax
- it means DS default segment ( == code16)
- and offset of V86eax (located into code32)
- CALCULATED FROM CODE16!!!!
- So be aware of where you declare data and from where you reference it.
- b)
- If you put too much stuff in code16 or code32 forcing the code
- accessed thru intersegment to use offsets beyound 64k you'll get a
- "hidden" protection violation (some assemblers don't detect it!!!!!)
- So if something strange happens, you know where to look at first.
-
- if you look into 386P remember:
- d16_ means DPMI stuff in code16
- d32_ means DPMI stuff in code32
- v16_ means VCPI stuff in code16
- v32_ means VCPI stuff in code32
- s16_ means MIXED stuff in code16
- s32_ means MIXED stuff in code32
-
- MIXED == shared between VCPI/DPMI xor "dos-exending" code
-
- ------------------------------------------------------------------------------
- Heres a list of the vars provided by PMODE to your program:
-
- _LoMemBase:dword
- Low mem base for allocation (first free byte).
-
- _LoMemTop:dword
- Top of low mem (last free byte +1).
-
- _HiMemBase:dword
- High mem base for allocation (first free byte).
-
- _HiMemTop:dword
- Top of high mem (last free byte +1).
-
- _PSPBase:dword
- Absolute linear address of start of PSP.
-
- _Code16Base:dword
- Absolute linear address of start of code16.
-
- _Code32Base:dword
- Absolute linear address of start of code32 (32bit code offset from this).
-
- _SelCode:word
- Code segment selector.
-
- _SelData:word
- Data segment alias selector for code.
-
- _SelZero:word
- Data segment starting at absolute 0.
-
- _386man:byte
- 386 manager flags, they have the following meanings
- (in the future they may also contain information about unified
- DMA services, timer services and more).
- bits:
- 0: 0=VCPI, 1=DPMI
- 1-7: undefined
-
- _GetIRQ:dword
- A pointer to the get IRQ function appropriate for the mode.
- The function takes arguments as follows:
- In:
- BL == IRQ num (0-0fh)
- Out:
- EDX == offset of current IRQ handler
-
- _SetIRQ:dword
- A pointer to the set IRQ function.
- In:
- BL == IRQ num (0-0fh)
- EDX == offset of new IRQ handler to set
-
- _OldInt:table of 256 dwords LOCATED IN THE CODE16 SEGMENT
- It contains all the original real mode int vectors found at
- 386P startup. Instead of storing "old" real mode interrupts yourself
- 386P does it for you. To chain to an old int just jump or pushf&call
- to the equivalent entry in _OldInt.
-
- ------------------------------------------------------------------------------
- And now some 'functions'. Remember, they ALL need:
- CS=_SelCode, DS=ES=FS=_Seldata, GS=_SelZero, DF=0 (CLD).
-
- _GetMem:
- Allocate any mem, (first checks low, then high)
- In:
- EAX == size requested
- Out:
- CF=0 memory allocated
- CF=1 not enough mem
- EAX == relative pointer to mem or undefined if not enough
-
- _GetLoMem:
- Allocate some low mem
- In:
- EAX == size requested
- Out:
- CF=0 memory allocated
- CF=1 not enough mem
- EAX == relative pointer to mem or undefined if not enough
-
- _GetHiMem:
- Allocate some high mem
- In:
- EAX == size requested
- Out:
- CF=0 memory allocated
- CF=1 not enough mem
- EAX == linear pointer to mem or undefined if not enough
-
- _GetIRQMask:
- Get status of IRQ mask bit (at port 21h or A1h)
- In:
- BL == IRQ num (0-15)
- Out:
- AL == status: 0=enabled, 1=disabled
-
- _SetIRQMask:
- Set status of IRQ mask bit
- In:
- BL == IRQ num (0-15)
- AL == status: 0=enabled, 1=disabled
-
- _Exit:
- Exit to real mode, restore initial IRQ mask
- restore timer 0 frequency to 18.2 Hz
- restore ALL interrupt vectors
- and get out setting video mode 03 (color text 80x25)
-
- ------------------------------------------------------------------------------
- PROGRAM SUPPORT
-
- I'm not going to go commercial with 386Power and its companion code.
- Maybe i will go commercial with the games i will produce with it
- (i'm already working on a "Commander Keen like" game)
- Anyway i will distribuite the sources of this and ALL the future releases
- of 386power and its companion code (386video, and all the other mode-x stuff).
-
- If 386Power doesn't work on your system i'd like to know (so i can fix it)
- you can reach me at the addresses listed in the end.
- Call me if you have suggestions about new improvements and things like that.
-
- BUT REMEMBER, 386power is NOT TOTALLY FREE (gosh!)
-
- If you use 386P "as is",you are NOT allowed to remove the messages
- displayed by the 386power startup code AND if you use it
- remember to include me and Tran (i owe it to him) in the list of who
- devenloped the software.
-
- If you modify 386P (not just cosmetic adjustments of course)
- you should use a different name (to avoid confusion)
- BUT you have to include almost the following message
- "based on the 386Power dos-extender by Lorenzo Micheletto MCHLNZ67T19C890A
- and on the PMODE dos-extender by Thomas 'Tran' Pytel".
-
- What's more if you make a commercial thing with it ....
- ... send me a free copy :).
-
- I won't ask anything more from you.
- It is not a free lunch ... it is a nearly free lunch.
-
- The main reason i coded 386P was for pure fun and get skilled about
- protected mode programming before coding the real game
- (if i just wanted a dos-extender i would have bought one from FlashTek).
- I distribuite it because: (in priority order)
- a) Needed a wider test base (just my 386 and the 486s' of some friend
- is a too restricted test base)
- b) I owe it to all the people who distribuited their sources on the net
- and let me learn how to handle the pc hardware and more.
- c) Need to get a reputation as a programmer, sooner or later
- when i will try to publish/sell my games it could be useful.
-
- ------------------------------------------------------------------------------
-
- Final things:
-
- 386Power has been designed with a restricted goal to reach
- (kick my code into 32bit protected mode :} and be sure that on program
- termination no bad things will happen).
- You are free to use it and change it any way you want, but please
- don't make protected mode viruses or trojan horse, i really hate those
- losers that think they are smart because they can destroy things.
- If you think you are smart, design and code a terrific piece of software.
-
- And as i said before 386P is limited to VCPI and DPMI (if you call it a limit).
- If you want a "real" dos-extender capable to handle anything
- contact the FlashTek guys and buy it
- or search the latest pmode release by Tran (Thomas Pytel) on internet.
-
- To reach FlashTek try to ask about them in the rec.games.programmer
- internet newsgroup.
-
- To find Tran, do the same or ...
- ....as far i know on may 1993 he could be reached on
- Creativity Demo Net or SBCnet as 'Tom Tran'
- or at the Sound Barrier: (718)979-6629, (718)979-9406
- or on Internet: tran@phantom.com
-
-
- If you want to contact me (for bug reports or other things)
- you can reach me ....
-
- On the internet as:
- knight@arianna.dei.unipd.it
- or
- knight@maya.dei.unipd.it
- or
- knight@paola.dei.unipd.it
- (Yeah! Multiple logins! I'm moving from a server to another, so you'd
- better send to both )
-
- By plain mail at the following address:
- Lorenzo Micheletto
- Via Piazza Miega 10/A
- Veronella (VERONA)
- ITALY 37040
-
- N.B. Maybe in 1995 i will be reachable only by plain mail
- ( i will be in the army for a year )
- but after that i will be back to Padova.
-
-